////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2017-2018 Qualcomm Technologies, Inc.
// All Rights Reserved.
// Confidential and Proprietary - Qualcomm Technologies, Inc.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file camxactuator.cpp
/// @brief Implements Actuator methods.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "camxincs.h"
#include "camxmem.h"
#include "camxcmdbuffer.h"
#include "camxcmdbuffermanager.h"
#include "camxcslsensordefs.h"
#include "camxhal3module.h"
#include "camxhwcontext.h"
#include "camxhwdefs.h"
#include "camximagesensormoduledata.h"
#include "camxpacket.h"
#include "camxactuator.h"
#include "camxsensornode.h"

CAMX_NAMESPACE_BEGIN

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Actuator::Actuator
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Actuator::Actuator(
    HwContext*    pHwContext,
    ActuatorData* pData)
{
    m_pHwContext           = pHwContext;
    m_pActuatorData        = pData;
    m_pMoveFocusPacket     = NULL;
    m_hActuatorDevice      = 0;
    m_initialConfigPending = TRUE;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Actuator::~Actuator
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Actuator::~Actuator()
{
    // These resources are managed manually, hence recycled manually.
    if (NULL != m_pMoveFocusCmdManager)
    {
        CAMX_DELETE m_pMoveFocusCmdManager;
        m_pMoveFocusCmdManager = NULL;
    }

    if (NULL != m_pMoveFocusPacketManager)
    {
        CAMX_DELETE m_pMoveFocusPacketManager;
        m_pMoveFocusPacketManager = NULL;
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Actuator::Create
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult Actuator::Create(
    ActuatorCreateData* pCreateData,
    INT32               actuatorDeviceIndex)
{
    CamxResult    result        = CamxResultEFailed;
    ActuatorData* pActuatorData = NULL;

    if (NULL != pCreateData)
    {
        HwContext* pHwContext = pCreateData->pHwContext;
        if (NULL != pHwContext)
        {
            // NOWHINE CP036a: exception
            pActuatorData = const_cast<ImageSensorModuleData*>(
                pHwContext->GetImageSensorModuleData(pCreateData->cameraId))->GetActuatorDataObject();

            if (NULL == pActuatorData)
            {
                CAMX_LOG_WARN(CamxLogGroupSensor, "ActuatorData is NULL");
                result = CamxResultEInvalidPointer;
            }
            else
            {
                pCreateData->pActuator = CAMX_NEW Actuator(pHwContext, pActuatorData);
                if (NULL != pCreateData->pActuator)
                {
                    result = pCreateData->pActuator->Initialize(pCreateData, actuatorDeviceIndex);
                }
                else
                {
                    CAMX_LOG_ERROR(CamxLogGroupSensor, "No memory for Actuator creation!");
                    result = CamxResultENoMemory;
                }
            }
        }

    }

    if (CamxResultSuccess == result)
    {
        CAMX_LOG_INFO(CamxLogGroupSensor, "Actuator created successfully!");
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "Actuator unavailable or initialization failed: %d!", result);
    }
    /// @todo (CAMX-673) make it non-fatal until KMD verified
    return CamxResultSuccess;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Actuator::Destroy
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID Actuator::Destroy()
{
    CamxResult    result        = CamxResultEFailed;
    MetadataPool* pMainPool     = NULL;

    if (NULL != m_pParentNode)
    {
        pMainPool = m_pParentNode->GetPerFramePool(PoolType::PerFrameResult);
    }

    if (NULL != pMainPool)
    {
        pMainPool->UnsubscribeAll(static_cast<IPropertyPoolObserver*>(this));
    }

    const StaticSettings* pStaticSettings = HwEnvironment::GetInstance()->GetStaticSettings();
    CAMX_ASSERT(pStaticSettings != NULL);
    BOOL bReleaseDevice = FALSE;

    if ((SensorSubDevicesCache::GetInstance()->CanRelease(m_cameraId)) ||
        (FALSE == pStaticSettings->enableSensorCaching))
    {
        bReleaseDevice = TRUE;
    }

    if ((NULL != m_pHwContext) && (TRUE == m_deviceAcquired) && (TRUE == bReleaseDevice))
    {
        ParkLens();
        result = CSLReleaseDevice(m_pHwContext->GetCSLSession(), m_hActuatorDevice);

        if (CamxResultSuccess == result)
        {
            m_deviceAcquired = FALSE;
            CAMX_LOG_INFO(CamxLogGroupSensor, "Actuator released successfully!");
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Actuator release failed: %d!", result);
        }
    }
    else
    {
        CAMX_LOG_INFO(CamxLogGroupSensor, "Actuator device handle: %p is cached", m_hActuatorDevice);
    }

    CAMX_DELETE this;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Actuator::CreateInitializePacket
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult Actuator::CreateInitializePacket()
{
    CamxResult       result               = CamxResultSuccess;
    UINT             I2CInfoCmdSize       = sizeof(CSLSensorI2CInfo);
    UINT             powerUpCmdSize       = m_pActuatorData->GetPowerSequenceCmdSize(TRUE);
    UINT             powerDownCmdSize     = m_pActuatorData->GetPowerSequenceCmdSize(FALSE);
    UINT             initializeCmdSize    = m_pActuatorData->GetInitializeCmdSize();
    PacketResource*  pPacketResource      = NULL;

    if (CamxResultSuccess == m_pI2CInfoCmdManager->GetBuffer(&pPacketResource))
    {
        CAMX_ASSERT(TRUE == pPacketResource->GetUsageFlags().cmdBuffer);

        // We know pResource actually points to a CmdBuffer so we may static_cast
        m_pI2CInfoCmdBuffer = static_cast<CmdBuffer*>(pPacketResource);
    }

    if (CamxResultSuccess == m_pPowerCmdManager->GetBuffer(&pPacketResource))
    {
        CAMX_ASSERT(TRUE == pPacketResource->GetUsageFlags().cmdBuffer);

        // We know pResource actually points to a CmdBuffer so we may static_cast
        m_pPowerCmdBuffer = static_cast<CmdBuffer*>(pPacketResource);
    }

    if (CamxResultSuccess == m_pInitializeCmdManager->GetBuffer(&pPacketResource))
    {
        CAMX_ASSERT(TRUE == pPacketResource->GetUsageFlags().cmdBuffer);

        // We know pResource actually points to a CmdBuffer so we may static_cast
        m_pInitializeCmdBuffer = static_cast<CmdBuffer*>(pPacketResource);
    }

    if (CamxResultSuccess == m_pInitializePacketManager->GetBuffer(&pPacketResource))
    {
        CAMX_ASSERT(TRUE == pPacketResource->GetUsageFlags().packet);

        // We know pResource actually points to a Packet so we may static_cast
        m_pPacket = static_cast<Packet*>(pPacketResource);
    }

    if ((NULL == m_pPacket) ||
        (NULL == m_pI2CInfoCmdBuffer) ||
        (NULL == m_pInitializeCmdBuffer) ||
        (NULL == m_pPowerCmdBuffer))
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor,
                       "Memory allocation failed Packet: %p, I2CCmdBuffer: %p, InitializeCmdBuffer: %p, m_pPowerCmdBuffer: %p",
                       m_pPacket,
                       m_pI2CInfoCmdBuffer,
                       m_pInitializeCmdBuffer,
                       m_pPowerCmdBuffer);
        result = CamxResultENoMemory;
    }
    else
    {
        VOID* pCmdBegin = m_pI2CInfoCmdBuffer->BeginCommands(I2CInfoCmdSize / sizeof(UINT32));
        if (NULL != pCmdBegin)
        {
            CSLSensorI2CInfo* pCmdI2CInfo = reinterpret_cast<CSLSensorI2CInfo*>(pCmdBegin);

            result = m_pActuatorData->CreateI2CInfoCmd(pCmdI2CInfo);
            if (CamxResultSuccess == result)
            {
                result = m_pI2CInfoCmdBuffer->CommitCommands();
            }
        }

        if ((CamxResultSuccess == result) && (0 != powerUpCmdSize))
        {
            VOID* pPowerUpCmdBegin = m_pPowerCmdBuffer->BeginCommands(powerUpCmdSize / sizeof(UINT32));
            if (NULL != pPowerUpCmdBegin)
            {
                if (CamxResultSuccess == m_pActuatorData->CreatePowerSequenceCmd(TRUE, pPowerUpCmdBegin))
                {
                    result = m_pPowerCmdBuffer->CommitCommands();
                }
            }
        }

        if ((CamxResultSuccess == result) && (0 != powerDownCmdSize))
        {
            VOID* pPowerDownCmdBegin = m_pPowerCmdBuffer->BeginCommands(powerDownCmdSize / sizeof(UINT32));
            if (NULL != pPowerDownCmdBegin)
            {
                if (CamxResultSuccess == m_pActuatorData->CreatePowerSequenceCmd(FALSE, pPowerDownCmdBegin))
                {
                    result = m_pPowerCmdBuffer->CommitCommands();
                }
            }
        }

        if (CamxResultSuccess == result)
        {
            pCmdBegin = m_pInitializeCmdBuffer->BeginCommands(initializeCmdSize / sizeof(UINT32));
            if (NULL != pCmdBegin)
            {
                VOID* pCmdInit = reinterpret_cast<CSLSensorProbeCmd*>(pCmdBegin);

                result = m_pActuatorData->CreateInitializeCmd(pCmdInit);
                if (CamxResultSuccess == result)
                {
                    result = m_pInitializeCmdBuffer->CommitCommands();
                }
            }
        }

        if (CamxResultSuccess == result)
        {
            // Not associated with any request. Won't be recycled.
            m_pPacket->SetOpcode(CSLDeviceTypeLensActuator, CSLPacketOpcodesActuatorInitialConfig);

            result = m_pPacket->AddCmdBufferReference(m_pI2CInfoCmdBuffer, NULL);
            {
                if (CamxResultSuccess == result)
                {
                    result = m_pPacket->AddCmdBufferReference(m_pPowerCmdBuffer, NULL);
                    if (CamxResultSuccess == result)
                    {
                        result = m_pPacket->AddCmdBufferReference(m_pInitializeCmdBuffer, NULL);
                        if (CamxResultSuccess == result)
                        {
                            result = m_pPacket->CommitPacket();
                        }
                    }
                }
            }
        }
    }

    if (CamxResultSuccess == result)
    {
        result = m_pHwContext->Submit(m_hActuatorDevice, m_pPacket);
    }

    m_pI2CInfoCmdManager->Recycle(m_pI2CInfoCmdBuffer);
    m_pInitializeCmdManager->Recycle(m_pInitializeCmdBuffer);
    m_pPowerCmdManager->Recycle(m_pPowerCmdBuffer);
    m_pInitializePacketManager->Recycle(m_pPacket);

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Actuator::Initialize
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult Actuator::Initialize(
    ActuatorCreateData* pCreateData,
    INT32               actuatorDeviceIndex)
{
    CamxResult   result              = CamxResultSuccess;
    Subscription subscription        = {UnitType::Property, PropertyIDAFFrameInfo};
    SubDeviceProperty actuatorDevice = SensorSubDevicesCache::GetInstance()->GetSubDevice(pCreateData->cameraId,
                                                                                          ActuatorHandle);

    m_pParentNode              = pCreateData->pParentNode;
    m_pInitializePacketManager = pCreateData->pInitPacketManager;
    m_pInitializeCmdManager    = pCreateData->pInitCmdManager;
    m_pI2CInfoCmdManager       = pCreateData->pI2CInfoCmdManager;
    m_pPowerCmdManager         = pCreateData->pPowerCmdManager;
    m_cameraId                 = pCreateData->cameraId;
    m_requestQueueDepth        = pCreateData->requestQueueDepth;

    CAMX_ASSERT(NULL != pCreateData->pPerUsecasePool);
    result = CalibrateActuatorData(pCreateData->pOTPData);
    if (CamxResultSuccess != result)
    {
        // Not returning failure as step table initialization can still proceed with the tuned values.
        CAMX_LOG_WARN(CamxLogGroupSensor, "Actuator data calibration failed, so proceeding with tuned values");
        result = CamxResultSuccess;
    }

    if (FALSE == actuatorDevice.isAcquired)
    {
        CAMX_LOG_INFO(CamxLogGroupSensor, "Initializing actuator for camerId: %d", pCreateData->cameraId);
        result = CSLAcquireDevice(m_pHwContext->GetCSLSession(),
                                  &m_hActuatorDevice,
                                  actuatorDeviceIndex,
                                  NULL,
                                  0,
                                  NULL,
                                  0,
                                  "SensorActuator");

        SensorSubDevicesCache::GetInstance()->SetSubDeviceHandle(pCreateData->cameraId, m_hActuatorDevice, ActuatorHandle);

        if (CamxResultSuccess == result)
        {
            m_deviceAcquired = TRUE;
            result = CreateInitializePacket();
            if (CamxResultSuccess != result)
            {
                CAMX_LOG_ERROR(CamxLogGroupSensor, "Failed for deviceIndex: %d", actuatorDeviceIndex);
            }
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor,
                           "AcquireDevice on Actuator failed deviceIndex: %d, result: %d",
                           actuatorDeviceIndex,
                           result);
        }
    }
    else
    {
        CAMX_ASSERT(actuatorDevice.hDevice != CSLInvalidHandle);
        CAMX_LOG_INFO(CamxLogGroupSensor,
                      "Reusing actuator device handle: %p for camerId: %d",
                      actuatorDevice.hDevice,
                      pCreateData->cameraId);
        m_hActuatorDevice = actuatorDevice.hDevice;
        m_deviceAcquired = TRUE;
    }

    if (CamxResultSuccess == result)
    {
        if (NULL != m_pParentNode)
        {
            m_pParentNode->AddCSLDeviceHandle(m_hActuatorDevice);
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Null Parent Node");
            return CamxResultEInvalidPointer;
        }

        result = CreateAndInitializeFocusPacketManager();

        if (CamxResultSuccess == result)
        {
            result = CreateAndInitializeFocusCmdBufferManager();
        }
    }

    if (CamxResultSuccess == result)
    {
        result = m_pActuatorData->InitializeStepTable();
    }

    if (CamxResultSuccess == result)
    {
        MetadataPool* pMainPool = m_pParentNode->GetPerFramePool(PoolType::PerFrameResult);

        if (NULL != pMainPool)
        {
            result = pMainPool->Subscribe(&subscription, 1, static_cast<IPropertyPoolObserver*>(this), "Actuator");
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Null Main Pool");
            result = CamxResultEResource;
        }
    }

    if (CamxResultSuccess == result)
    {
        if (GetCurrentPosition(PositionUnit::Step) != InvalidLensData)
        {
            MoveFocus(GetCurrentPosition(PositionUnit::Step), PositionUnit::Step, 0, 0);
        }
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Actuator::CreateAndInitializeFocusPacketManager
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult Actuator::CreateAndInitializeFocusPacketManager()
{
    CamxResult result = CamxResultSuccess;

    ResourceParams packetResourceParams                = { 0 };
    packetResourceParams.usageFlags.packet             = 1;
    packetResourceParams.packetParams.maxNumCmdBuffers = 1;
    packetResourceParams.packetParams.maxNumIOConfigs  = 0;
    packetResourceParams.resourceSize                  = Packet::CalculatePacketSize(&packetResourceParams.packetParams);
    packetResourceParams.poolSize                      = (m_requestQueueDepth * packetResourceParams.resourceSize);
    packetResourceParams.alignment                     = CamxPacketAlignmentInBytes;
    packetResourceParams.pDeviceIndices                = NULL;
    packetResourceParams.numDevices                    = 0;
    packetResourceParams.memFlags                      = CSLMemFlagKMDAccess | CSLMemFlagUMDAccess;

    m_pMoveFocusPacketManager= CAMX_NEW CmdBufferManager();
    if (NULL != m_pMoveFocusPacketManager)
    {
        result = m_pMoveFocusPacketManager->Initialize(&packetResourceParams);
    }
    else
    {
        result = CamxResultENoMemory;
    }
    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Actuator::CreateAndInitializeFocusCmdBufferManager
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult Actuator::CreateAndInitializeFocusCmdBufferManager()
{
    CamxResult result                      = CamxResultSuccess;

    ResourceParams cmdResourceParams       = { 0 };
    UINT           moveFocusCmdSize        = m_pActuatorData->GetMaxMoveFocusCmdSize();

    cmdResourceParams.resourceSize          = moveFocusCmdSize;
    cmdResourceParams.poolSize              = (m_requestQueueDepth * moveFocusCmdSize);
    cmdResourceParams.usageFlags.cmdBuffer  = 1;
    cmdResourceParams.cmdParams.type        = CmdType::I2C;
    cmdResourceParams.alignment             = CamxCommandBufferAlignmentInBytes;
    cmdResourceParams.pDeviceIndices        = NULL;
    cmdResourceParams.numDevices            = 0;
    cmdResourceParams.memFlags              = CSLMemFlagKMDAccess | CSLMemFlagUMDAccess;

    m_pMoveFocusCmdManager = CAMX_NEW CmdBufferManager();
    if (NULL != m_pMoveFocusCmdManager)
    {
        result = m_pMoveFocusCmdManager->Initialize(&cmdResourceParams);
    }
    else
    {
        result = CamxResultENoMemory;
    }
    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Actuator::ParkLens
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID Actuator::ParkLens()
{
    /// @todo (CAMX-852) Destroy nodes before CSLStreamOff (when actuator is powered off in KMD)
    if (ActuatorType::VCM == m_pActuatorData->GetActuatorLibrary()->slaveInfo.actuatorType)
    {
        UINT currentPosition = static_cast<UINT>(GetCurrentPosition(PositionUnit::DAC));

        while (currentPosition > 0)
        {
            // Move in different pace to reduce park lens time
            if (currentPosition > ParkLensPaceBoundary[3])
            {
                currentPosition -= ParkLensPaceBoundary[3];
            }
            else if (currentPosition > ParkLensPaceBoundary[2])
            {
                currentPosition -= ParkLensPaceBoundary[2];
            }
            else if (currentPosition > ParkLensPaceBoundary[1])
            {
                currentPosition -= ParkLensPaceBoundary[1];
            }
            else if (currentPosition > ParkLensPaceBoundary[0])
            {
                currentPosition -= ParkLensPaceBoundary[0];
            }
            else
            {
                currentPosition = 0;
            }

            MoveFocus(currentPosition, PositionUnit::DAC, 0, ParkLensDelayMilliseconds);
        }
    }
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Actuator::MoveFocus
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult Actuator::MoveFocus(
    INT          targetPosition,
    PositionUnit unit,
    UINT64       requestId,
    UINT16       additionalDelay)
{
    CamxResult                  result          = CamxResultSuccess;
    PacketResource*             pPacketResource = NULL;
    CSLPacketOpcodesActuator    opcode;

    if (CamxResultSuccess == m_pMoveFocusCmdManager->GetBuffer(&pPacketResource))
    {
        CAMX_ASSERT(TRUE == pPacketResource->GetUsageFlags().cmdBuffer);

        // We know pResource actually points to a CmdBuffer so we may static_cast
        m_pMoveFocusCmdBuffer = static_cast<CmdBuffer*>(pPacketResource);
    }

    if (CamxResultSuccess == m_pMoveFocusPacketManager->GetBuffer(&pPacketResource))
    {
        CAMX_ASSERT(TRUE == pPacketResource->GetUsageFlags().packet);

        // We know pResource actually points to a Packet so we may static_cast
        m_pMoveFocusPacket = static_cast<Packet*>(pPacketResource);
    }

    if ((NULL == m_pMoveFocusPacket) || (NULL == m_pMoveFocusCmdBuffer))
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "Invalid buffer FocusPacket: %p, MoveFocusCmdBuffer: %p",
                       m_pMoveFocusPacket, m_pMoveFocusCmdBuffer);
        result = CamxResultENoMemory;
    }
    else
    {
        INT focusCmdSize = m_pActuatorData->GetMoveFocusCmdSize(additionalDelay);

        VOID* pCmdBegin = m_pMoveFocusCmdBuffer->BeginCommands(focusCmdSize / sizeof(UINT32));
        if (NULL != pCmdBegin)
        {
            VOID* pCmd = reinterpret_cast<CSLSensorI2CInfo*>(pCmdBegin);

            result = m_pActuatorData->CreateMoveFocusCmd(targetPosition, unit, pCmd, additionalDelay);
            if (CamxResultSuccess == result)
            {
                result = m_pMoveFocusCmdBuffer->CommitCommands();
            }
        }
        if (CamxResultSuccess == result)
        {
            m_pMoveFocusCmdBuffer->SetRequestId(m_pParentNode->GetCSLSyncId(requestId));
            m_pMoveFocusPacket->SetRequestId(m_pParentNode->GetCSLSyncId(requestId));

            opcode = CSLPacketOpcodesActuatorMove;
            if (FALSE == m_pParentNode->IsPipelineStreamedOn())
            {
                if (TRUE == m_initialConfigPending)
                {
                    opcode                 = CSLPacketOpcodesActuatorInitialConfig;
                    m_initialConfigPending = FALSE;
                }
            }
            else
            {
                m_initialConfigPending = TRUE;
            }

            m_pMoveFocusPacket->SetOpcode(CSLDeviceTypeInvalidDevice, opcode);

            result = m_pMoveFocusPacket->AddCmdBufferReference(m_pMoveFocusCmdBuffer, NULL);
        }
        if (CamxResultSuccess == result)
        {
            result = m_pMoveFocusPacket->CommitPacket();
        }

        if (CamxResultSuccess == result)
        {
            CAMX_LOG_INFO(CamxLogGroupSensor, "Submit MoveFocus packet, targetPosition: %d", targetPosition);
            result = m_pHwContext->Submit(m_hActuatorDevice, m_pMoveFocusPacket);
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Failed: %d", result);
        }

        m_pMoveFocusCmdManager->Recycle(m_pMoveFocusCmdBuffer);

        m_pMoveFocusPacketManager->Recycle(m_pMoveFocusPacket);
    }
    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Actuator::GetCurrentPosition
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT Actuator::GetCurrentPosition(
    PositionUnit unit)
{
    return m_pActuatorData->GetCurrentPosition(unit);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Actuator::GetSensitivity
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FLOAT Actuator::GetSensitivity()
{
    return m_pActuatorData->GetSensitivity();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Actuator::OnPropertyUpdate
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID Actuator::OnPropertyUpdate(
    PropertyID  id,
    UINT64      requestId,
    UINT        pipelineId)
{
    MetadataPool* pPerFramePool = m_pParentNode->GetPerFramePool(PoolType::PerFrameResult);
    CAMX_ASSERT(PropertyIDAFFrameInfo == id);
    CAMX_ASSERT(NULL != pPerFramePool);
    CAMX_UNREFERENCED_PARAM(pipelineId);
    MetadataSlot* pSlot = NULL;

    if (NULL != pPerFramePool)
    {
        pSlot = pPerFramePool->GetSlot(requestId);
    }

    if (NULL != pSlot)
    {
        MainPropertyBlob* pBlob = NULL;

        // Lock not needed. By contract, only AF updates AFFrameInfo, and will have completed for the notify to come, so
        // there is no chance of half populated data or another entity changing it while read is outstanding

        pSlot->GetPropertyBlob(reinterpret_cast<VOID**>(&pBlob));

        if (NULL != pBlob)
        {
            MoveLensOutput*       pMoveLens            = &pBlob->mAFFrameInfo.moveLensOutput;
            const StaticSettings* pStaticSettings      = HwEnvironment::GetInstance()->GetStaticSettings();
            BOOL                  overrideLensPosition =
                (AFManualLensControlLogical == pStaticSettings->manualAf) ? TRUE : FALSE;
            UINT32                targetLensPosition   =
                (FALSE == overrideLensPosition) ? pMoveLens->targetLensPosition : pStaticSettings->lensPos;

            if (pMoveLens->useDACValue == FALSE)
            {
                if ((GetCurrentPosition(PositionUnit::Step) != static_cast<INT>(targetLensPosition)) ||
                    (TRUE == overrideLensPosition))
                {
                    CAMX_LOG_VERBOSE(CamxLogGroupSensor, "Moving actuator using logical lens position");
                    MoveFocus(targetLensPosition, PositionUnit::Step, requestId, 0);
                    CAMX_LOG_VERBOSE(CamxLogGroupSensor, "Actuator Move Done");
                }
            }
            else
            {
                if ((GetCurrentPosition(PositionUnit::DAC) != static_cast<INT>(targetLensPosition)) ||
                    (TRUE == overrideLensPosition))
                {
                    CAMX_LOG_VERBOSE(CamxLogGroupSensor, "Moving actuator using DAC position");
                    MoveFocus(targetLensPosition, PositionUnit::DAC, requestId, 0);
                    CAMX_LOG_VERBOSE(CamxLogGroupSensor, "Actuator Move Done");
                }
            }
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Actuator::CalibrateActuatorData
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult Actuator::CalibrateActuatorData(
    const EEPROMOTPData* pOTPData)
{
    CamxResult    result            = CamxResultSuccess;

    if (NULL != pOTPData)
    {
        if (TRUE == pOTPData->AFCalibration.isAvailable)
        {
            result = m_pActuatorData->CalibrateActuatorDriverData(&pOTPData->AFCalibration);
        }
        else
        {
            CAMX_LOG_WARN(CamxLogGroupSensor, "AF OTP Data is not available");
            result = CamxResultEFailed;
        }
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "OTP Data is not available");
        result = CamxResultEFailed;
    }

    return result;
}

CAMX_NAMESPACE_END
